import hashlib
from math import ceil

class TorrentTags:
    fileName = "NAME"
    trackerUrl = "TRACKER"
    size = "SIZE"
    chunkSize = "CHUNK"
    fileHash = "FILEHASH"
    pieceHash = "HASH"


def verifyTorrent(torrentFile, fileName):

    class TorrentTags:
    	fileName = "NAME"
    	trackerUrl = "TRACKER"
    	size = "SIZE"
    	chunkSize = "CHUNK"
    	fileHash = "FILEHASH"
    	pieceHash = "HASH"

    def createTorrent(fileName, trackerUrl, chunkSize):
        tags = {}
        fileObj = open(fileName, "rb")
        chunkSizeKb = chunkSize *1024 #Convert to KB
        tags[TorrentTags.fileName] = fileName 
        tags[TorrentTags.trackerUrl] = trackerUrl 
        piecesHash = []
        md5 = hashlib.md5()
        fileSize = 0
        while True:
            data = fileObj.read(chunkSizeKb)
            if not data:
                break
            pieceHash = hashlib.sha1(data).hexdigest()#Tell that you use hexdigest
            #tags[TorrentTags.pieceHash] += [pieceHash] 
            piecesHash.append(pieceHash)
            md5.update(data)
            fileSize += len(data)
        fileHash = md5.hexdigest()
        tags[TorrentTags.fileHash]= fileHash 
        tags[TorrentTags.size] = str(fileSize)
        tags[TorrentTags.chunkSize] = str(chunkSize)
        tags[TorrentTags.pieceHash] = piecesHash
        
        #The next part is self-checking
        fileSize = int(tags[TorrentTags.size])
        chunkSizeKB = int(tags[TorrentTags.chunkSize])*1024
        expectedPieces = int(ceil(fileSize*1.0/chunkSizeKB))
        if expectedPieces != len(tags[TorrentTags.pieceHash]):
            print "Wrong number of file piece."
            print "Expected: " , expectedPieces
            print "Got: " , len(tags[TorrentTags.pieceHash])
            raise ValueError
        
        tags[TorrentTags.size] = fileSize #Put it as int
        tags[TorrentTags.chunkSize] = chunkSizeKB/1024#Put it as int
        
        return tags
    #End of createTorrent Function
    #############################

    
    def parseTorrent(torrentFile):
        torrent = open(torrentFile, "r")
        lines = torrent.readlines()
        
        tags = {}
        order = [TorrentTags.fileName,
                 TorrentTags.trackerUrl,
                 TorrentTags.size,
                 TorrentTags.chunkSize,
                 TorrentTags.fileHash,
                 TorrentTags.pieceHash]
    
        tags[TorrentTags.pieceHash] = []
        for line in lines:
            if line.strip() == "":
                continue
            tokens = line.split(":",1)#Make only one split
            if len(tokens) == 1:
                print "Invalid File Format"
                print "Didn't find ':' at line: ", len(order)
                return 
            keyword = tokens[0]
            keyword = keyword.upper()
            if keyword != order[0]:
                #Lets ease the debugging.
                if keyword in order:
                    print "Invalid Sequence found in torrent file."
                    print "Expected: " + order[0] + "\tFound: " + keyword
                else:
                    print "Unknown Tag found in torrent file"
                    print "Found: " + keyword
                return 
            else:
                param = tokens[1]
                param = param.strip()
                #I've found tag that was expected according to sequence
                if len(order) != 1:# #More stupid design
                    #It's piece Hash, it can get repeated any number of times
                    order.pop(0)#Forward to the next tag.
                    tags[keyword] = param
                else:
                    tags[keyword] += [param]
                            
        if len(order) != 1:
            print "Incomplete Torrent File"
            return
        
        fileSize = int(tags[TorrentTags.size])
        chunkSizeKB = int(tags[TorrentTags.chunkSize])*1024
        expectedPieces = int(ceil(fileSize*1.0/chunkSizeKB))
        
        if expectedPieces != len(tags[TorrentTags.pieceHash]):
            print "Wrong number of file piece."
            print "Expected: " , expectedPieces
            print "Got: " , len(tags[TorrentTags.pieceHash])
            raise ValueError
        tags[TorrentTags.size] = fileSize #Put it as int
        tags[TorrentTags.chunkSize] = chunkSizeKB/1024#Put it as int
        return tags
    #End of parseTorrent Function
    #############################

    torrDict = parseTorrent(torrentFile)
    actualDict = createTorrent(fileName, 
                               torrDict[TorrentTags.trackerUrl], 
                               int(torrDict[TorrentTags.chunkSize]))
    
    for key in actualDict.keys():
        if actualDict[key] != torrDict[key]:
            print "Verification failed in : " , key
            print "Expected: ", actualDict[key],
            print "\tGot: " , torrDict[key]
            #print "\n\n\n\n"
            return False
    return True


if __name__ == '__main__':
    fileName = "Camel - Lawrence.flv"
    torrName = "Lawrence.tor"
    assert verifyTorrent(torrName,fileName), True
